#ifndef   PROG_H
#define   PROG_H

// Max flash size
#define		MAX_FLASH_SIZE  (128*1024ul)
// Flash page size
#define     PAGE_SIZE		(512)
#define     PAGE_MASK       (~(PAGE_SIZE-1))

#define  LDROM_BASE				0x00100000ul
#define  APROM_BASE             0x0ul

#define  PARAM_BASE             (4096-512)
#define  VALID_FLAG             (0x00abcdef)

/* APP Flag is used to determine the application is update success */
#define  APP_FLAG_ADDR			(128*1024-512)
#define  APP_VALID				(0xfeedbacc)

#define  RESET_REASON_ADDR		(0x20000000 + 4096 - 4)
#define  RESET_REASON_USER      (0xbaccfeed)
#define  IsUserReset()			(*((uint32_t*)RESET_REASON_ADDR) == RESET_REASON_USER)
#define  SetUserReset()			(*((uint32_t*)RESET_REASON_ADDR) = RESET_REASON_USER)
#define  ClearUserReset()       (*((uint32_t*)RESET_REASON_ADDR) = 0)

#define  INITIAL_PROG			0x05	   /* get string request to initial program */
#define  CONFIG_PROG            0x06       /* get string request to start config word program */
#define  RESET2APROM			0x07       /* reset to APROM */
#define  RESET2LDROM            0x08	   /* reset to LDROM */
//extern uint32_t g_u32FlashSize;	           /* current device flash size */
extern uint8_t  g_u8SecurityLockBit;       /* security bit status */
//extern uint32_t g_u32FlashBaseAddress;	   /* flash base address */
extern uint32_t g_u32DataBaseAddress;      /* data flash base address */

#define  CFG0_ADDR		0x00300000
#define  CFG1_ADDR      0x00300004

typedef enum
{
    PS_Initial,	  /* Initial program */
	PS_Update,	  /* Program in progress */
	PS_Pending,   /* Send data is pending */
	PS_Done,	  /* Program done */

	PS_Config,    /* Config word program word */

	PS_Reset,	  /* reset device */
	PS_Unknown = -1,
}ProgState;

typedef struct tagInitBlock
{
    uint8_t  cipher[16];
    uint32_t  startAddress;
    uint32_t  length;
    uint32_t  crc;
    uint32_t  blockCount;
    uint32_t  unused[16-4-4];
}InitBlock_t,*PInitBlock_t;

typedef struct tagProgBlock   /* Program block definition */
{
    uint32_t   addr;       // Data address
    uint32_t   data[15];   // data content
}ProgBlock_t,*PProgBlock_t;

typedef struct tagConfigProg
{
	uint32_t   bRead;      // zero mean write, none zero means read
	uint32_t   config0;    // value for config 0
	uint32_t   config1;    // value for config 1
	uint32_t   dummy[13];  // reserved
}ConfigProg_t,*PConfigProg_t;

typedef struct tagDevParam
{
	uint32_t   flag;   	// must be VALID_FLAG
	uint16_t   sn[10];    // serial number
	uint8_t    key[32]; // aes key table
}DevParam_t,*PDevParam_t;

#define   devParam            ((PDevParam_t)PARAM_BASE) 

extern ProgState progState;			   /* program state */

void   InitialROMProgram(uint32_t crc, uint32_t length, uint32_t blockCnt);

void   OnInitialProg(void);
void   OnConfigProg(void);
void   OnRecvData(uint32_t* data);
void   OnSendDataDone(void);
void   SendData(const uint8_t* data);

// Make sure all data in the same page
void ProgramROM(uint32_t address, const uint32_t* buf, uint32_t size);

// 0 means fail, other success
uint32_t  CheckROM(void);
#endif
